Java 读书笔记8 多态

多态

## # 动态绑定

  1. 也很好理解,简单地说,方法接受的是父类,方法里面具体用到的是什么就随便了
    1
    2
    3
    4
    5
    void test(Parent a)
    {
    a.find(); //此处的a可以使子类对象,那么test整体方法最后绑定就是动态的啦,否则它不知道到底是谁调用的;
    //该方法动态的绑定到了子类的find方法;
    }

## # 父类的神奇作用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public class Art {
Art (int i)
{
System.out.println("Art Constructior");
}
void test()
{
System.out.println("art");
}
}
public class Drawing extends Art {
public static void main (String arg[])
{
Art a = new Drawing(); //父类引用用子类对象
a.test(); //a引用只能调用父类有的方法,但是如果子类幼虫在,那么调用子类方法;
}
void test()
{
System.out.println("aaa");
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class Art {
public static void main (String a[])
{
Art art = new Drawing();
art.test1(); //编译器明确表示。这个test1()方法是私有的,就是Art自己的
}
private void test1()
{
System.out.println("test1");
}
}
public class Drawing extends Art {
public void test1 () //私有方法外面根本看不到,怎么可能重写。
{
System.out.println("public");
}
}

## 为什么会存在get/set方法?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class Art {
String a = "aaaaa";
void test()
{
System.out.println("art");
}
}
public class Drawing extends Art {
String a = "bbbbbb";
public static void main (String arg[])
{
Art a = new Drawing();
a.test(); //test调用的子类的
System.out.println(a.a); //属性a 是调用父类的
}
void test()
{
System.out.println("aaa");
}
}

为何会存在这样的问题呢?一个引用,他的方法使用子类,属性使用子类,这就是因为绑定,方法是动态绑定的,属性是前期绑定的,他不在乎你运行时是谁的;
因此我们一般将属性设置为私有(final),通过get/set方法实现调用值;由于方法是动态绑定的,我们就可以找到相应的值了;

## 为什么一定要从父类开始继承

首先,我们想一下,一个类中是可以没有构造方法的;如果没有的话,就会自动创造

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
public class Art {
Art ()
{
System.out.println("art");
}
}
public class Drawing extends Art {
public static void main (String arg[])
{
Drawing drawing = new Drawing(); //没有构造函数,自动调用父类构造函数,那么其实是他自己的默认构造函数调用了父类;因为什么?需要父类初始化啊;即便父类的构造函数也不存在初始化,也必须调用,万一初始化了呢;
//另外,假设不调用父类,大概,就不能称之为子类了;因为你完全没有继承过程啊
}
}
```
## ## 关于销毁顺序
其实也很好理解,创造是自上到下,销毁肯定是自下而上;
## ## 初始化的真实顺序
1. 在所有之前,将分配给对象的存储空间初始化为二进制零;
2. 从父类开始调用构造函数;
3. 按照声明顺序调用成员的初始化;
4. 子类构造函数主体开始
## ## 协变返回
目前不知道有啥用。。。。
## ## 用继承进行设计
```java
class Actor {
public void act() {
}
}
class HappyActor extends Actor {
public void act() {
System.out.println("HappyActor");
}
}
class SadActor extends Actor {
public void act() {
System.out.println("SadActor");
}
}
class Stage {
private Actor actor = new HappyActor(); //父类的神奇用法
public void change() { //类型转换
actor = new SadActor();
}
public void performPlay() {
actor.act();
}
}
public class Transmogrify {
public static void main(String[] args) {
Stage stage = new Stage();
stage.performPlay();
stage.change();
stage.performPlay();
}
}

通过父类作为桥梁,就可以在子类之间变换;
一条通用的准则: 用继承表达行为间的差异,并用字段表达状态上的变化;

## 向下转型与运行时类别识别

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public class Useful {
public void f ()
{
}
public void g()
{
}
}
public class MoreUseful extends Useful{
public static void main(String a[])
{
Useful [] x = {
new Useful(),
new MoreUseful()
};
x[0].f();
x[1].g();
((MoreUseful)x[1]).h(); //必须强制转换,我觉得说不定是在转换引用;
}
public void f(){}
public void g(){}
public void h(){}
}